home *** CD-ROM | disk | FTP | other *** search
Text File | 2009-04-30 | 26.7 KB | 1,028 lines |
- #!/usr/bin/perl
-
- #/*
- #* Copyright (C) 2005-2006 Pontus Fuchs, Giridhar Pemmasani
- #*
- #*
- #* This program is free software; you can redistribute it and/or modify
- #* it under the terms of the GNU General Public License as published by
- #* the Free Software Foundation; either version 2 of the License, or
- #* (at your option) any later version.
- #*
- #* This program is distributed in the hope that it will be useful,
- #* but WITHOUT ANY WARRANTY; without even the implied warranty of
- #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- #* GNU General Public License for more details.
- #*
- #*/
-
- use strict;
- use Fcntl ':mode';
- use File::Basename;
- use File::Copy;
- use File::Path;
- use Cwd;
-
- $ENV{PATH} = "/sbin:/usr/sbin:$ENV{PATH}";
-
- my $WRAP_PCI_BUS = 5;
- my $WRAP_PCMCIA_BUS = 8;
- my $WRAP_USB_BUS = 15;
-
- my %sections;
- my %parsed_sections;
- my $confdir = "/etc/ndiswrapper";
- my $src_dir;
- my $driver_name;
- my @source_disks_files;
-
- my $re_dev_id = "([[:xdigit:]]{4})";
- my $re_sub_dev_conf = "$re_dev_id:$re_dev_id:$re_dev_id:$re_dev_id" .
- "\.([[:xdigit:]]+)\.conf";
- my $re_dev_conf = "$re_dev_id:$re_dev_id\.([[:xdigit:]]+)\.conf";
-
- # fixup list for parameters.
- my %param_fixlist = ("EnableRadio|0" => "1",
- "IBSSGMode|0" => "2",
- "PrivacyMode|0" => "2",
- "MapRegisters|256" => "64",
- "AdhocGMode|1" => "0");
-
- if (@ARGV < 1) {
- usage();
- exit(1);
- }
-
- my $modconf;
- if (`uname -r` =~ /(\d+)\.(\d+)\.(\d+)/) {
- if ($2 > 4) {
- if (-d "/etc/modprobe.d") {
- $modconf = "/etc/modprobe.d/ndiswrapper";
- } else {
- $modconf = "/etc/modprobe.conf";
- }
- } else {
- if (-d "/etc/modutils") {
- $modconf = "/etc/modutils/ndiswrapper";
- } else {
- $modconf = "/etc/modules.conf";
- }
- }
- }
-
- my $res;
- my $dbg_file;
-
- $dbg_file = "/dev/null";
-
- # "-D" is for development/debugging only
- if ($ARGV[0] eq "-D") {
- $dbg_file = "/tmp/ndiswrapper.dbg";
- $confdir = "/tmp/ndiswrapper";
- shift;
- }
-
- open(DBG, "> $dbg_file") or die "couldn't open $dbg_file: $!";
-
- if ($ARGV[0] eq "-i" and @ARGV == 2) {
- $res = install($ARGV[1]);
- } elsif (($ARGV[0] eq "-a" or $ARGV[0] eq "-d") and @ARGV == 3) {
- $res = device_driver_alias($ARGV[1], $ARGV[2]);
- } elsif (($ARGV[0] eq "-e" or $ARGV[0] eq "-r") and @ARGV == 2) {
- $res = remove_driver($ARGV[1]);
- } elsif ($ARGV[0] eq "-l" and @ARGV == 1) {
- $res = list_drivers();
- } elsif ($ARGV[0] eq "-m" and @ARGV == 1) {
- $res = add_module_alias();
- } elsif ($ARGV[0] eq "-v" and @ARGV == 1) {
- $res = check_version();
- } elsif ($ARGV[0] eq "-ma" and @ARGV == 1) {
- $res = generate_module_device_map(0);
- } elsif ($ARGV[0] eq "-mi" and @ARGV == 1) {
- $res = generate_module_device_map(1);
- } else {
- usage();
- }
- close(DBG);
- exit($res);
-
- sub usage() {
- print "install/manage Windows drivers for ndiswrapper\n\n" .
- "usage: ndiswrapper OPTION\n" .
- "-i inffile install driver described by 'inffile'\n" .
- "-a devid driver use installed 'driver' for 'devid' (dangerous)\n" .
- "-r driver remove 'driver'\n" .
- "-l list installed drivers\n" .
- "-m write configuration for modprobe\n" .
- "-ma write module alias configuration for all devices\n" .
- "-mi write module install configuration for all devices\n" .
- "-v report version information\n\n" .
- "where 'devid' is either PCIID or USBID of the form XXXX:XXXX,\n" .
- "as reported by 'lspci -n' or 'lsusb' for the card\n";
- }
-
- sub remove_driver {
- my $driver = shift;
- if (!rmtree("$confdir/$driver", 0, 1)) {
- warn "couldn't delete $confdir/$driver: $!\n";
- }
- return 0;
- }
-
- sub abort {
- remove_driver($driver_name);
- exit 1;
- }
-
- sub check_version {
- my ($utils_version, $module_utils_version, $res);
- $res = 0;
- $utils_version = `loadndisdriver -v`;
- chomp($utils_version);
- $utils_version =~ s/^version: //;
- if (length($utils_version) eq 0) {
- printf "utils version is too old!\n";
- $res = -1;
- }
- $module_utils_version = 0;
- open(MODINFO, "modinfo ndiswrapper |");
- while (my $line = <MODINFO>) {
- if ($line =~ /utils_version:.*read only:\s([0-9\.]+)/) {
- $module_utils_version = $1;
- last;
- }
- }
- if ($module_utils_version eq 0) {
- printf "module version is too old!\n";
- $res = -1;
- } elsif ($utils_version ne $module_utils_version) {
- printf "utils version '%s' is incompatible with utils version needed" .
- " by driver ('%s')!\n", $utils_version, $module_utils_version;
- $res = -1;
- }
- printf "utils version: '%s', utils version needed by module: '%s'\n",
- $utils_version, $module_utils_version;
- printf "module details:\n";
- system("modinfo ndiswrapper | grep -E '^(version|vermagic|filename)'");
-
- if ($res) {
- printf "\nYou may need to upgrade driver and/or utils to latest " .
- "versions available at\n" .
- "http://ndiswrapper.sourceforge.net\n";
- }
- return $res;
- }
-
- sub install {
- my $inf = shift;
- chomp($inf);
- $src_dir = dirname($inf);
- $driver_name = lc(basename($inf));
- unless ($driver_name =~ s/\.inf$//) {
- die "install argument must be .inf file\n";
- }
-
- if (! -d $confdir) {
- mkdir($confdir) or die "couldn't create $confdir: $!";
- }
- (-d "$confdir/$driver_name") and
- die "driver $driver_name is already installed\n";
- read_sections($inf);
- parse_section("Strings");
- parse_section("Version");
- parse_source_disks_files();
- mkdir("$confdir/$driver_name") or
- die "couldn't create $confdir/$driver_name: $!";
- print "installing $driver_name ...\n";
- parse_mfr();
- copy_file(basename($inf), basename($inf));
- create_fuzzy_conf($driver_name);
- return 0;
- }
-
- # return lines in section
- sub get_section {
- my $name = shift;
- foreach my $key (keys %sections) {
- if (lc($key) eq lc($name)) {
- printf DBG "section: $key\n";
- return \@{$sections{$key}};
- }
- }
- printf DBG "couldn't find section \"$name\"\n";
- return 0;
- }
-
- # load inf and split into different sections.
- sub read_sections {
- my $filename = shift;
- open(INF, $filename) or die "couldn't open $filename: $!";
-
- my $name = "none";
- @{$sections{$name}} = ();
- while (my $line = <INF>) {
- # convert from unicode
- $line =~ s/\xff\xfe//;
- $line =~ s/\0//g;
-
- chomp($line);
- $line = trim($line);
- next if ($line =~ /^$/);
- if ($line =~ /^\[(.+)\]/) {
- $name = $1;
- @{$sections{$name}} = ();
- } else {
- push(@{$sections{$name}}, $line);
- }
- }
- close(INF);
- foreach $name (keys %sections) {
- printf DBG "section: %s\n", $name;
- foreach my $line (@{$sections{$name}}) {
- printf DBG "%s: %s\n", $name, $line;
- }
- }
- }
-
- sub parse_section {
- my $name = shift;
- my $lines = get_section($name);
- if (!$lines) {
- return;
- }
- $parsed_sections{$name} = ();
- foreach my $line (@{$lines}) {
- (my $key, my $val) = parse_key_value($line);
- if ($key) {
- $val = strip_quotes($val);
- $parsed_sections{$name}->{$key} = $val;
- printf DBG "$name: %s = %s\n", $key, $val;
- }
- }
- }
-
- sub parse_mfr() {
- my $lines = get_section("Manufacturer");
- $lines or die "couldn't get manufacturer section - " .
- "installation may be incomplete\n";
- foreach my $line (@{$lines}) {
- my ($strkey, $val) = parse_key_value($line);
- if ($strkey) {
- my ($models, @targets) = split(",", $val);
- if ($models) {
- printf DBG "mfr: %s, %s\n", $line, $models;
- my $target = choose_target_os(@targets);
- printf DBG "target: '%s'\n", $target;
- parse_models($models, $target);
- }
- }
- }
- }
-
- sub parse_models {
- my ($models, $target) = @_;
- printf DBG "models: target: '%s'.'%s'\n", $models, $target;
- my $lines = get_target_os_section($models, $target);
- if (!$lines) {
- warn "couldn't find models section \"$models\" -\n" .
- "installation may be incomplete\n";
- return -1;
- }
- foreach my $line (@{$lines}) {
- $line = del_comment($line);
- next if (length($line) eq 0);
- (my $dev_desc, my $val) = parse_key_value($line);
- my @fields = split(",", $val);
- if (@fields le 1) {
- printf "couldn't find install directive: %s\n", $line;
- next;
- }
- my $section = trim($fields[0]);
- my $hwid = trim($fields[1]);
- if ($hwid =~ /^%.+%$/) {
- $hwid = get_string_value($hwid);
- }
- # TODO: deal with compatible IDs as hwid?
- my ($bus_type, $vendor, $device, $subvendor, $subdevice) =
- parse_hwid($hwid);
- next if (!$vendor);
- printf DBG "models: %s, %s, %s\n", $section, $hwid, $vendor;
- parse_install($section, $target, $bus_type, $vendor, $device,
- $subvendor, $subdevice);
- }
- }
-
- sub parse_install {
- my ($section, $target, $bus_type, $vendor, $device,
- $subvendor, $subdevice) = @_;
- my $lines = get_target_os_section($section, $target);
- if (!$lines) {
- warn "couldn't find install section \"$section\" -\n" .
- "installation may be incomplete\n";
- return -1;
- }
-
- my $filename = "$vendor:$device";
- if ($subvendor) {
- $filename .= ":$subvendor:$subdevice"
- }
- $filename .= sprintf(".%X.conf", $bus_type);
-
- my (@addregs, @copyfiles);
- foreach my $line (@{$lines}) {
- $line =~ s/^;\s*//;
- $line = trim(del_comment($line));
- my ($key, $val) = parse_key_value($line);
- my @array;
- if ($key) {
- if (lc($key) eq "addreg") {
- @array = split(",", $val);
- foreach my $reg (@array) {
- push @addregs, trim($reg);
- }
- } elsif (lc($key) eq "copyfiles") {
- printf DBG "copyfiles: %s\n", $val;
- @array = split(",", $val);
- foreach my $copy_file_dirs (@array) {
- my @copy_sec = split(",", $copy_file_dirs);
- foreach my $file (@copy_sec) {
- push @copyfiles, trim($file);
- }
- }
- } elsif (lc($key) eq "bustype") {
- printf DBG "bustype: %s\n", $val;
- $bus_type = $val;
- }
- }
- }
-
- open(CONF, ">$confdir/$driver_name/$filename") or
- die "couldn't create file $confdir/$driver_name/$filename: $!";
-
- printf CONF "sys_files|";
- foreach my $file (@copyfiles) {
- parse_copy_file($file);
- }
- printf CONF "\n";
-
- my $version = get_section_value("Version", "DriverVer");
- my $provider = get_section_value("Version", "Provider");
- my $classguid = get_section_value("Version", "ClassGUID");
- my $providerstring = trim(strip_quotes(get_string_value(trim($provider))));
- $classguid =~ s/^\s*{//;
- $classguid =~ s/}\s*$//;
-
- printf CONF "NdisVersion|0x50001\n";
- printf CONF "Environment|1\n";
- printf CONF "class_guid|%s\n", $classguid;
- printf CONF "driver_version|%s,%s\n", $providerstring, $version;
- printf CONF "BusType|%s\n", $bus_type;
- printf CONF "SlotNumber|01\n";
- printf CONF "NetCfgInstanceId|{28022A01-1234-5678-ABCDE-123813291A00}\n";
- printf CONF "\n";
- close(CONF);
-
- open(CONF, "|sort|uniq >>$confdir/$driver_name/$filename") or
- die "couldn't create file $confdir/$driver_name/$filename: $!";
-
- foreach my $reg (@addregs) {
- parse_registry($reg);
- }
- close(CONF);
- }
-
- sub parse_registry {
- my ($reg, $conf) = @_;
- my $lines = get_section($reg);
- if (!$lines) {
- warn "couldn't find section \"$reg\" -\n" .
- "installation may be incomplete\n";
- return -1;
- }
-
- my $driver_desc = 0;
- foreach my $line (@{$lines}) {
- $line = del_comment($line);
- my @fields = split(",", $line);
- next if (@fields lt 4);
- my $value;
- my $param = trim($fields[1]);
- if ($param =~ /^ndi\\/i) {
- if ($param =~ /^ndi\\params\\(.+)/i) {
- $param = strip_quotes(trim($1));
- $param =~ s/\\.*$//;
- next if (lc(trim($fields[2])) ne "default");
- $value = strip_quotes(trim($fields[4]));
- } else {
- printf DBG "ignoring parameter $line\n";
- next;
- }
- } else {
- $param = strip_quotes(trim($fields[2]));
- next if (length($param) eq 0);
- $value = strip_quotes(trim($fields[4]));
- }
- $value = get_string_value($value);
- if (length($param) gt 0) {
- if ($param_fixlist{"$param|$value"}) {
- my $orig_value = $value;
- $value = $param_fixlist{"$param|$value"};
- printf "forcing parameter $param from $orig_value to $value\n";
- }
- printf CONF "%s|%s\n", $param, $value;
- if ($param =~ /^DriverDesc$/) {
- $driver_desc = 1;
- }
- }
- }
- if ($driver_desc == 0) {
- printf CONF "DriverDesc|NDIS Network Adapter\n";
- }
- }
-
- sub parse_copy_file {
- my $copy_name = shift;
-
- if ($copy_name =~ /^\@/) {
- $copy_name =~ s/^\@//;
- $copy_name = trim($copy_name);
- if (valid_copy_file_name($copy_name)) {
- return copy_file($copy_name, $copy_name);
- }
- }
-
- my $lines = get_section($copy_name);
- if (!$lines) {
- warn "couldn't find section \"$copy_name\" -\n" .
- "installation may be incomplete\n";
- return -1;
- }
- foreach my $line (@{$lines}) {
- $line = trim($line);
-
- # some inf files have file names commented out; get file names from them
- $line =~ s/^\s*;//;
- my @files = split(",", $line);
- if (@files == 0) {
- printf DBG "copyfiles section $copy_name has no files\n";
- return -1;
- }
- my $src, my $dst;
- if (@files > 1 and length(trim($files[1])) > 0) {
- $src = $files[1];
- if (length(trim($files[0])) > 0) {
- $dst = $files[0];
- } else {
- $dst = $src;
- }
- } else {
- $src = $files[0];
- $dst = $src;
- }
- $src =~ s/^.*\\//;
- $dst =~ s/^.*\\//;
- printf DBG "src: '%s', dst: '%s'\n", $src, $dst;
- $src = trim(del_comment($src));
- next if (length($src) eq 0);
- if (valid_copy_file_name($src)) {
- $dst = trim(del_comment($dst));
- printf DBG "src: '%s', dst: '%s'\n", $src, $dst;
- copy_file($src, $dst);
- } else {
- printf DBG "invalid file '%s' ignored\n", $src;
- }
- }
- return 0;
- }
-
- sub parse_hwid {
- my $hwid = uc(shift);
- if ($hwid =~ /(PCI\\)?VEN_(\w+)&DEV_(\w+)&SUBSYS_(\w{4})(\S{4})/) {
- return ($WRAP_PCI_BUS, $2, $3, $4, $5);
- } elsif ($hwid =~ /(PCI\\)?VEN_(\w+)&DEV_(\w+)/) {
- return ($WRAP_PCI_BUS, $2, $3, 0, 0);
- } elsif ($hwid =~ /(USB\\)?VID_(\w+)&PID_(\w+)/) {
- return ($WRAP_USB_BUS, $2, $3, 0, 0);
- } else {
- return 0;
- }
- }
-
- sub parse_key_value {
- my $line = shift;
-
- $line = del_comment($line);
- if ($line =~ /([^=]+)=(.+)/) {
- return (trim($1), trim($2));
- } else {
- return 0;
- }
- }
-
- sub choose_target_os {
- my @targets = @_;
- my $arch = `uname -m`;
- chomp($arch);
- printf DBG "arch: %s\n", $arch;
- if ($arch =~ /64$/) {
- $arch = "amd64";
- } else {
- $arch = "x86";
- }
- printf DBG "arch: %s\n", $arch;
- my @prefs = ("NT($arch)\.5\.1", "NT($arch)\.5", "NT($arch)",
- "NT\.5\.1", "NT\.5", "NT");
- foreach my $pref (@prefs) {
- foreach my $target (@targets) {
- $target = trim($target);
- printf DBG "target: '%s', pref: '%s'\n", $target, $pref;
- if ($target =~ /NT((amd64)|(x86))/i) {
- printf DBG "target arch: '%s'\n", $1;
- next if ($1 !~ /$arch/i);
- }
- if ($target =~ /$pref/i) {
- return $target;
- }
- }
- }
- return "";
- }
-
- sub get_target_os_section {
- my ($section, $target) = @_;
- my $lines;
-
- chomp($section);
- $section =~ s/^\s*"\s*//;
- $section =~ s/\s*"\s*$//;
- printf DBG "section: \"%s\", target: \"%s\"\n", $section, $target;
-
- if (length($target) gt 0) {
- $lines = get_section($section . "." . $target);
- return $lines if ($lines);
- }
-
- my $arch = `uname -m`;
- chomp($arch);
- printf DBG "arch: %s\n", $arch;
- if ($arch =~ /64$/) {
- $arch = "AMD64";
- } else {
- $arch = "X86";
- }
- printf DBG "arch: %s\n", $arch;
-
- my @prefs = ("NT$arch.5.1", "NT$arch.5", "NT$arch",
- "NT.5.1", "NT.5", "NT");
- foreach my $pref (@prefs) {
- $lines = get_section($section . "." . $pref);
- return $lines if ($lines);
- }
- $lines = get_section($section);
- return $lines if ($lines);
-
- printf DBG "couldn't find section \"$section\" for \"$arch\"\n";
- return 0;
- }
-
- sub get_section_value {
- (my $section, my $name) = @_;
- return $parsed_sections{$section}->{$name};
- }
-
- sub get_string_value {
- my $key = shift;
- if ($key =~ /%(.+)%/) {
- $key = $1;
- return get_section_value("Strings", $key);
- } else {
- return $key;
- }
- }
-
- sub copy_file {
- my ($src, $dst) = @_;
-
- # ignore files not needed
- return 0 if (lc($src) =~ /\.((exe)|(dll)|(cpl)|(hlp))$/);
- my $real_file = get_file($src);
- if (length($real_file) gt 0) {
- $dst = lc($dst);
- printf DBG "copying \"$src_dir/$real_file\" to " .
- "\"$confdir/$driver_name/$dst\"\n";
- copy("$src_dir/$real_file", "$confdir/$driver_name/$dst") or
- warn "couldn't copy \"$src_dir/$real_file\" to " .
- "\"$confdir/$driver_name\": $! -\n" .
- "installation may be incomplete\n";
- printf DBG "chmod: $confdir/$driver_name/$dst\n";
- chmod(0644, "$confdir/$driver_name/$dst");
- if ($dst =~ /\.sys$/) {
- printf CONF "%s ", $dst;
- }
- } else {
- warn "couldn't find \"$src\" in \"$src_dir\"; make sure " .
- "all driver files, including .inf, .sys (and any firmware files) " .
- "are in \"$src_dir\" -\n" .
- "installation may be incomplete\n";
- }
- }
-
- # for conf files with subvendor and subdevice, create conf files with just
- # vendor and device
- sub create_fuzzy_conf {
- my $driver = shift;
- my $cwd = cwd();
- chdir("$confdir/$driver") or die "couldn't chdir to $confdir/$driver: $!";
- open(LS, "ls -1 . |") or die "couldn't open $confdir/$driver: $!";
- while (my $file = <LS>) {
- chomp($file);
- if ($file =~ /$re_sub_dev_conf/) {
- my $fuzzy_file = "$1:$2.$5.conf";
- printf DBG "file: $file, fuzzy file: $fuzzy_file\n";
- if (! -e "$confdir/$driver/$fuzzy_file") {
- symlink("$file", "$fuzzy_file") or
- warn "couldn't link $confdir/$driver/$file " .
- "to $confdir/$driver/$fuzzy_file: $!\n";
- }
- }
- }
- close(LS);
- chdir($cwd) or warn "couldn't chdir to $cwd: $!";
- return 0;
- }
-
- # find a file in a case-insensitive way.
- sub get_file {
- my $file = lc(shift);
- if (opendir(DIR, "$src_dir")) {
- my @allfiles = readdir(DIR);
- foreach my $real_file (@allfiles) {
- if (lc($real_file) eq $file) {
- closedir(DIR);
- return $real_file;
- }
- }
- closedir(DIR);
- } else {
- warn "couldn't open \"$src_dir\": $! -\n" .
- "installation may be incomplete\n";
- }
- return "";
- }
-
- sub strip_quotes {
- my $s = shift;
- $s =~ s/"(.*)"/$1/;
- return $s;
- }
-
- sub del_comment {
- my $s = shift;
- $s =~ s/;.*//;
- return $s;
- }
-
- # remove whitsepace at front and end.
- sub trim {
- my $s = shift;
- $s =~ s/^\s*//;
- $s =~ s/\s*$//;
- return $s;
- }
-
- sub valid_copy_file_name {
- my $file = shift;
- $file = lc($file);
- printf DBG "file name: %s\n", $file;
- foreach my $disk_file (@source_disks_files) {
- return 1 if ($file eq $disk_file);
- }
- # some inf files may not have SourceDisksFiles section, so use
- # known file names
- return 1 if ($file =~ /\.((sys)|(bin)|(out))$/);
- return 0;
- }
-
- sub parse_source_disks_files {
- my $lines = get_source_disks_files();
- if ($lines) {
- foreach my $line (@{$lines}) {
- $line = del_comment($line);
- next if (length($line) eq 0);
- my @file = split("=", $line);
- next if (@file eq 0 or length($file[0] eq 0));
- printf DBG "source disk file: \"%s\"\n", trim($file[0]);
- push (@source_disks_files, lc(trim($file[0])));
- }
- } else {
- warn "couldn't find SourceDisksFiles section - " .
- "continuing anyway...\n";
- }
- }
-
- sub get_source_disks_files {
- my $arch = `uname -m`;
- chomp($arch);
- if ($arch =~ /64$/) {
- $arch = "AMD64";
- } else {
- $arch = "X86";
- }
-
- my $lines = get_section("SourceDisksFiles." . $arch);
- return $lines if ($lines);
-
- $lines = get_section("SourceDisksFiles");
- return $lines if ($lines);
-
- return 0;
- }
-
- sub device_driver_alias {
- my ($devid, $driver) = @_;
- my $done = 0;
-
- $devid = uc($devid);
- if (!($devid =~ /^$re_dev_id:$re_dev_id$/)) {
- printf "'$devid' is not a valid device ID\n";
- return 1;
- }
- open(LS, "ls -1 $confdir/$driver/ |") or
- die "couldn't open $confdir/$driver: $!";
-
- while (my $f = <LS>) {
- chomp($f);
- if ($f =~ /\.([[:xdigit:]]+)\.conf$/) {
- if (stat("$confdir/$driver/$devid.$1.conf")) {
- printf "Driver '$driver' is already used for '$devid'\n";
- $done = 1;
- last;
- }
- if (symlink("$f", "$confdir/$driver/$devid.$1.conf")) {
- printf "WARNING: Driver '$driver' will be used for '$devid'\n" .
- "This is safe _only_ if driver $driver is meant for " .
- "chip in device $devid\n";
- $done = 1;
- last;
- } else {
- warn "couldn't create symlink for \"$f\": $! -\n" .
- "installation may be incomplete\n";
- }
- }
- }
- close(LS);
- if ($done == 0) {
- printf "driver '$driver' is not installed (properly)!\n";
- return 1;
- }
- return 0;
- }
-
- sub generate_module_device_map {
- my $mode = shift;
- my ($vendor, $device, $subvendor, $subdevice, $bustype, $busid);
-
- my $device_map;
- if (-d "/etc/modprobe.d") {
- $device_map = $modconf;
- } elsif (-d "/etc/modules.d") {
- $device_map = "/etc/modules.d/ndiswrapper";
- } else {
- $device_map = "/etc/ndiswrapper/ndiswrapper";
- }
-
- open(DEVMAP, "| sort >$device_map") or
- die "couldn't create modules alias file $device_map: $!";
- open(LS, "ls -1 $confdir|") or
- die "couldn't open $confdir: $!";
- while (my $driver = <LS>) {
- chomp($driver);
- my $stat = (stat("$confdir/$driver"))[2];
- if (S_ISDIR($stat)) {
- open(LS2, "ls -1 $confdir/$driver/ |") or
- die "couldn't open $confdir/$driver: $!";
- while (my $file = <LS2>) {
- chomp ($file);
- if ($file =~ /\.conf$/) {
- if ($file =~ /^$re_sub_dev_conf$/) {
- ($vendor, $device, $subvendor, $subdevice, $busid) =
- (uc($1), uc($2), "0000$3", "0000$4", hex($5));
- } elsif ($file =~ /^$re_dev_conf$/) {
- ($vendor, $device, $subvendor, $subdevice, $busid) =
- (uc($1), uc($2), "*", "*", hex($3));
- }
- my $devstring;
- if ($busid eq $WRAP_USB_BUS or $busid eq 0) {
- $devstring = sprintf("usb:v%sp%sd*dc*dsc*dp*ic*isc*ip*",
- $vendor, $device);
- } elsif ($busid eq $WRAP_PCI_BUS) {
- $devstring = sprintf("pci:v0000%sd0000%ssv%ssd%sbc*sc*i*",
- $vendor, $device, $subvendor,
- $subdevice);
- } else {
- warn "wrong bustype ($busid) for " .
- "configuration file $file - ignoring it\n";
- next;
- }
- if ($mode == 0) {
- printf DEVMAP "alias %s ndiswrapper\n", $devstring;
- } else {
- printf DEVMAP "install %s /sbin/modprobe ndiswrapper\n",
- $devstring;
- }
- }
- }
- close(LS2);
- }
- }
- close(LS);
- close(DEVMAP);
-
- printf "module configuration information is stored in $device_map\n";
- return 0;
- }
-
- sub list_drivers {
- my $cards = get_cards();
-
- open(LS, "ls -1 $confdir|") or die "couldn't open $confdir: $!";
- while (my $driver = <LS>) {
- chomp($driver);
- if (-e "$confdir/$driver") {
- printf "%s : %s\n", $driver, install_status($cards, $driver);
- }
- }
- close(LS);
- return 0;
- }
-
- sub add_module_alias {
- my $alias = 0;
-
- open(MODPROBE, "modprobe -c|") or die "couldn't run modprobe: $!";
- while (my $line = <MODPROBE>) {
- if ($line =~ /^alias\s.+\sndiswrapper/) {
- printf "module configuration already contains alias directive\n\n";
- $alias = 1;
- } elsif ($line =~ /^install\s.*ndiswrapper/) {
- warn "module configuration contains directive $line;" .
- "you should delete that";
- } elsif ($line =~ /^post-install\s+ndiswrapper/) {
- warn "module configuration contains directive $line;" .
- "you should delete that";
- }
- }
- close(MODPROBE);
-
- if ($alias) {
- return 0;
- }
-
- printf "adding \"alias wlan0 ndiswrapper\" to $modconf ...\n";
- system("echo \"alias wlan0 ndiswrapper\" >>$modconf") == 0 or
- die "couldn't add module alias: $!";
- if (-x "/sbin/update-modules") {
- system("/sbin/update-modules");
- }
- return 0;
- }
-
- sub get_cards {
- #01:00.0 Class 0300: 1002:4c66 (rev 01)
- # Subsystem: 1043:1732
- my @cards = ();
- if (open(LSPCI, "lspci -vn|")) {
- my $card;
- while (my $line = <LSPCI>) {
- if ($line =~ /^[0-9a-f]+.+\s$re_dev_id:$re_dev_id/) {
- $card = {vendor => uc($1), device => uc($2)};
- printf DBG "card: %s, %s\n", $1, $2;
- } elsif ($line =~ /.+Subsystem:\s$re_dev_id:$re_dev_id/) {
- $card->{subvendor} = uc($1);
- $card->{subdevice} = uc($2);
- printf DBG "sub: %s, %s\n", $1, $2;
- push(@cards, $card);
- }
- }
- close(LSPCI);
- }
-
- if (open(LSUSB, "lsusb |")) {
- my $card;
- while (my $line = <LSUSB>) {
- if ($line =~ /.+: ID\s$re_dev_id:$re_dev_id/) {
- $card = {vendor => uc($1), device => uc($2)};
- push(@cards, $card);
- }
- }
- close(LSUSB);
- }
- return \@cards;
- }
-
- sub install_status {
- my ($cards, $driver) = @_;
-
- if (!$cards or !$driver) {
- return;
- }
-
- my ($sys, $conf, $inf);
- my ($vendor, $device, $subvendor, $subdevice, $busid, $ret);
-
- $sys = $conf = $inf = 0;
- open(LS2, "ls -1 $confdir/$driver|") or
- die "couldn't open $confdir/$driver: $!";
- while (my $file = <LS2>) {
- chomp($file);
- if ($file =~ /\.sys$/) {
- $sys = 1;
- } elsif ($file =~ /\.inf$/) {
- $inf = 1;
- } elsif ($file =~ /^$re_sub_dev_conf$/) {
- $busid = hex($5);
- $conf = 1 if ($busid eq $WRAP_PCI_BUS);
- } elsif ($file =~ /^$re_dev_conf$/) {
- $busid = hex($3);
- $conf = 1 if ($busid eq $WRAP_USB_BUS or $busid eq 0 or
- $busid eq $WRAP_PCI_BUS);
- }
- }
- close(LS2);
- printf DBG "status: $sys, $inf, $conf\n";
- if ($sys eq 0 or $inf eq 0 or $conf eq 0) {
- $ret = "invalid driver!";
- return $ret;
- }
- $ret = "driver installed";
- open(LS2, "ls -1 $confdir/$driver|") or
- die "couldn't open $confdir/$driver: $!";
-
- while (my $file = <LS2>) {
- chomp($file);
- next if ($file !~ /\.conf$/);
- $conf = 0;
- if ($file =~ /^$re_sub_dev_conf$/) {
- ($vendor, $device, $subvendor, $subdevice, $busid) =
- (uc($1), uc($2), uc($3), uc($4), hex($5));
- $conf = 1;
- foreach my $card (@{$cards}) {
- if ($card->{vendor} eq $vendor and
- $card->{device} eq $device and
- $card->{subvendor} eq $subvendor and
- $card->{subdevice} eq $subdevice and
- $busid eq $WRAP_PCI_BUS) {
- $ret .= "\n\tdevice ($vendor:$device" .
- ":$subvendor:$subdevice) present";
- $conf = 2;
- last;
- }
- }
- } elsif ($file =~ /^$re_dev_conf/) {
- ($vendor, $device, $subvendor, $subdevice, $busid) =
- (uc($1), uc($2), "\\*", "\\*", hex($3));
- $conf = 1;
- foreach my $card (@{$cards}) {
- if ($card->{vendor} eq $vendor and
- $card->{device} eq $device and
- ($busid eq $WRAP_USB_BUS or $busid eq 0 or
- $busid eq $WRAP_PCI_BUS)) {
- $ret .= "\n\tdevice ($vendor:$device) present";
- $conf = 2;
- last;
- }
- }
- }
- next if ($conf le 1);
- # find if kernel knows of an alternate driver for this device
- my $devstring;
- if ($busid eq $WRAP_USB_BUS or $busid eq 0) {
- $devstring = sprintf("usb:v%sp%sd", $vendor, $device);
- } elsif ($busid eq $WRAP_PCI_BUS) {
- $devstring = sprintf("pci:v0000%sd0000%ssv", $vendor, $device);
- } else {
- next;
- }
- open(MODPROBE, "modprobe -c|") or next;
- while (my $line = <MODPROBE>) {
- my $alt;
- chomp($line);
- next if $line !~ /$devstring/;
- $alt = (split(' ', $line))[-1];
- chomp($alt);
- if (length($alt) gt 0 and $alt ne "ndiswrapper") {
- $ret .= " (alternate driver: $alt)";
- last;
- }
- }
- close(MODPROBE);
- }
- close(LS2);
- printf DBG "driver: $driver, $ret\n";
- return $ret;
- }
-
- ## Local Variables: ##
- ## cperl-indent-level: 4 ##
- ## End: ##
-